package ar.com.altaagenda.spiders;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.htmlparser.Node;
import org.htmlparser.Parser;
import org.htmlparser.filters.NodeClassFilter;
import org.htmlparser.tags.Bullet;
import org.htmlparser.tags.BulletList;
import org.htmlparser.tags.Div;
import org.htmlparser.tags.HeadingTag;
import org.htmlparser.tags.LinkTag;
import org.htmlparser.tags.ParagraphTag;
import org.htmlparser.tags.Span;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.SimpleNodeIterator;

import ar.com.altaagenda.Result;
import ar.com.altaagenda.utils.ElementAttributeFilter;
import ar.com.altaagenda.utils.HttpExecutor;

public class VASpider extends SheSpider{

	private static final String CHARSET = "iso-8859-1";
	private static final String DOMAIN = "http://www.vuenosairez.com/";
	private static final String TEL_PREFIX = "Tel:";
	private static final String MAIL_PREFIX = "Mail:";
	private static final String WEB_PREFIX = "Web:";
	private static final Pattern HOUR_PATTERN = Pattern.compile("\\d\\d\\.\\d\\d");
	
	public VASpider(Calendar startDate, Calendar endDate){
		super(startDate, endDate);
	}
	
	public List<Result> getResults() {
		
		ArrayList<Result> results = new ArrayList<>();
		
		for(Calendar date = (Calendar)startDate.clone(); date.before(endDate); date.add(Calendar.DAY_OF_YEAR, 1)){
			System.out.println("Buscando resultados en " + this.getSiteName() +" para la fecha: " + dateFormater.format(date.getTime()));

			//Up to 20 as we expect never to have more than 20 pages 
			for(int i=1; i<20; i++){
				String url = this.generateUrl(date, i);
				
				try{
					String htmlBody = new HttpExecutor(CHARSET).execute(url);
						 
					Parser parser = new Parser();
					parser.setInputHTML(htmlBody);
		
					NodeList list = parser.extractAllNodesThatMatch(new ElementAttributeFilter(Div.class,"class"," slot vevent"));
					SimpleNodeIterator divs = list.elements();
			
					//If no divs are found it means that no results are found, no need to process results then, need to break in order
					//not to ask for further pages and save http requests.
					if(!divs.hasMoreNodes()){
						break;
					}
					System.out.println("Procesando resultados para la pagina: " + i);
					
					//Iterates over the results
					while (divs.hasMoreNodes()) {
						Node div = divs.nextNode();
						
						parser.setInputHTML(div.toHtml());
						list = parser.extractAllNodesThatMatch(new NodeClassFilter(LinkTag.class));
						Node resultLink = list.elements().nextNode();
						
						String detailsUrl = this.generateDetailsUrl(((LinkTag)resultLink));
						results.add(this.getResult(detailsUrl, date));
					}
				} catch (Exception ex){
					System.out.println("Exception caught trying to crawl this url: " + url);
					ex.printStackTrace();
				}
			}
		}
		
		return results;
	}
	
	private Result getResult(String detailsUrl, Calendar date) throws Exception{
		String htmlBody = new HttpExecutor(CHARSET).execute(detailsUrl);

		Parser parser = new Parser();
		parser.setInputHTML(htmlBody);
		String resultDiv = parser.extractAllNodesThatMatch(new ElementAttributeFilter(Div.class,"class","info vevent ")).elementAt(0).toHtml();

		String nombreEvento = this.extractNombreEvento(resultDiv);
		List<String> artistas = this.extractArtista(resultDiv, nombreEvento);
		String fecha = this.dateFormater.format(date.getTime());
		String hora = this.extractHora(resultDiv);
		String lugar = this.extractLugar(resultDiv);
		
		parser.setInputHTML(resultDiv);
		String datosLugar = parser.extractAllNodesThatMatch(new ElementAttributeFilter(BulletList.class,"class","adr lista")).elementAt(0).toHtml();
		
		String direccionLugar = this.extractDir(datosLugar);
		String barrioLugar = this.extractBarrio(datosLugar);
		String telLugar = this.extractTel(datosLugar);
		String mailLugar = this.extractMail(datosLugar);
		String webLugar = this.extractWeb(datosLugar);
		
		return new Result(nombreEvento, artistas, fecha, hora, lugar, direccionLugar, barrioLugar, webLugar, mailLugar, telLugar, this.getSiteName());
	}

	private String extractNombreEvento(String resultHtml) throws Exception{
		Parser parser = new Parser();
		parser.setInputHTML(resultHtml);
		
		Node title = parser.extractAllNodesThatMatch(new ElementAttributeFilter(HeadingTag.class, "class", "summary titulos")).elementAt(0);
		return this.removeTagsAndEnters(title.toHtml());
	}

	private List<String> extractArtista(String resultHtml, String nombreEvento) throws Exception{
		Parser parser = new Parser();
		parser.setInputHTML(resultHtml);
		
		Node h5Artistas = parser.extractAllNodesThatMatch(new ElementAttributeFilter(Div.class, "class", "artistas")).elementAt(0);
		parser.setInputHTML(h5Artistas.toHtml());
		NodeList linksArtistas = parser.extractAllNodesThatMatch(new NodeClassFilter(LinkTag.class));
		
		List<String>artistas = new ArrayList<String>();
		SimpleNodeIterator it = linksArtistas.elements(); 
		while (it.hasMoreNodes()) {
			LinkTag link = (LinkTag) it.nextNode();
			artistas.add(link.getLinkText());
		}
		
		//If no artist were found
		if(artistas.isEmpty()){
			artistas.add(nombreEvento);
		}
		
		return artistas;
	}

	private String extractHora(String html) throws Exception{
		Parser parser = new Parser();
		parser.setInputHTML(html);
		
		Node result = parser.extractAllNodesThatMatch(new ElementAttributeFilter(ParagraphTag.class, "class", "fecha")).elementAt(0);
		
		Matcher matcher = HOUR_PATTERN.matcher(this.removeTagsAndEnters(result.toHtml()));
		if(matcher.find()){
			return matcher.group();
		} else {
			return SheSpider.NOT_FOUND; 
		}
	}

	private String extractLugar(String resultHtml) throws Exception{
		Parser parser = new Parser();
		parser.setInputHTML(resultHtml);
		
		Node title = parser.extractAllNodesThatMatch(new ElementAttributeFilter(Span.class, "class", "fn org")).elementAt(0);
		return this.removeTagsAndEnters(title.toHtml());
	}

	private String extractDir(String html) throws Exception {
		Parser parser = new Parser();
		parser.setInputHTML(html);
		
		Node address = parser.extractAllNodesThatMatch(new ElementAttributeFilter(Bullet.class, "class", "street-address")).elementAt(0);
		
		return this.removeTagsAndEnters(address.toHtml());
	}
	
	private String extractBarrio(String html) throws Exception{
		Parser parser = new Parser();
		parser.setInputHTML(html);
		
		Node barrio = parser.extractAllNodesThatMatch(new NodeClassFilter(Bullet.class)).elementAt(1);
		
		String barrioString = this.removeTagsAndEnters(barrio.toHtml());
		
		return barrioString == null || barrioString.isEmpty() ? SheSpider.NOT_AVAILABLE : barrioString.trim();
	}
	
	private String extractTel(String html) throws Exception{
		Parser parser = new Parser();
		parser.setInputHTML(html);
		
		Node telefono = parser.extractAllNodesThatMatch(new ElementAttributeFilter(Bullet.class, "class", "telefono")).elementAt(0);
		
		String telString = this.removeTagsAndEnters(telefono.toHtml());
		
		if(telString != null && telString.indexOf(TEL_PREFIX) >= 0){
			telString = telString.replace(TEL_PREFIX, "");
		}
		
		return telString == null || telString.isEmpty() ? SheSpider.NOT_AVAILABLE : telString.trim();
	}
	
	private String extractMail(String html) throws Exception{
		Parser parser = new Parser();
		parser.setInputHTML(html);
		
		Node mail = parser.extractAllNodesThatMatch(new ElementAttributeFilter(Bullet.class, "class", "mail")).elementAt(0);
		
		String mailString = this.removeTagsAndEnters(mail.toHtml());
		
		if(mailString != null && mailString.indexOf(MAIL_PREFIX) >= 0){
			mailString = mailString.replace(MAIL_PREFIX, "");
		}
		
		return mailString == null || mailString.isEmpty() ? SheSpider.NOT_AVAILABLE : mailString.trim();
	}
	
	private String extractWeb(String html) throws Exception{
		Parser parser = new Parser();
		parser.setInputHTML(html);
		
		Node web = parser.extractAllNodesThatMatch(new ElementAttributeFilter(Bullet.class, "class", "web")).elementAt(0);
		
		String webString = this.removeTagsAndEnters(web.toHtml());
		
		if(webString != null && webString.indexOf(WEB_PREFIX) >= 0){
			webString = webString.replace(WEB_PREFIX, "");
		}
		
		return webString == null || webString.isEmpty() ? SheSpider.NOT_AVAILABLE : webString.trim();
	}
	
	private String generateDetailsUrl(LinkTag detailsLink){
		//substring to skip the "../"
		return detailsLink.extractLink();
	}
	
	private String generateUrl(Calendar date, int pageNumber){
		return DOMAIN + "V2_1/v2-resultados-agenda.php?pag="+pageNumber+"&tipoBusq=26&cat=recital&dia="+date.get(Calendar.DAY_OF_MONTH)+"&mes="+(date.get(Calendar.MONTH)+1)+"&anio="+date.get(Calendar.YEAR)+"&tipoQuery=hoy&zona=Ciudad-de-Buenos-Aires";
	}
	
	@Override
	protected String getSiteName() {
		return "VuenosAirez";
	}
}